package com.yy.studyspringboot.utils;

import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.Function;

@Component
public class FunctionUtils<T,R> {

    /**
     * 校验势力的参数为空，抛出异常
     * @param t 入参实例
     * @param functions 可变参数
     * throws 抛出空指针异常
     */
    public void  verifyParamEmpty(T t, SFunction<T, Object>... functions){
        for (SFunction<T, Object> fn : functions) {
            if (Objects.isNull(fn.apply(t))){
                throw new NullPointerException("参数"+ getFieldName(fn) +"为空");
            }
        }
    }

    /**
     * 获取字段名
     */
    private String getFieldName(SFunction<T, Object> fn) {
        SerializedLambda serializedLambda = getSerializedLambda(fn);
        // 从lambda信息取出method、field、class等
        String fieldName = serializedLambda.getImplMethodName().substring("get".length());
        fieldName = fieldName.replaceFirst(fieldName.charAt(0) + "", (fieldName.charAt(0) + "").toLowerCase());
        return fieldName;
    }

    /**
     * 获取序列化的Lambda
     */
    private static <T> SerializedLambda getSerializedLambda(SFunction<T, ?> fn) {
           // 从function取出序列化方法
           Method writeReplaceMethod;
           try {
               writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
           } catch (NoSuchMethodException e) {
               throw new RuntimeException(e);
           }

            // 从序列化方法取出序列化的lambda信息
            boolean isAccessible = writeReplaceMethod.isAccessible();
            writeReplaceMethod.setAccessible(true);
            SerializedLambda serializedLambda;
            try {
                    serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(fn);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            writeReplaceMethod.setAccessible(isAccessible);
            return serializedLambda;
    }


    @FunctionalInterface
    public interface SFunction<T, R> extends Function<T, R>, Serializable {
    }

}
